package com.smsc.headend.task.engine.handler.impl.whitelist;

import cn.hutool.core.date.SystemClock;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.smsc.headend.common.enums.DeviceType;
import com.smsc.headend.module.asset.dto.DcuDTO;
import com.smsc.headend.module.asset.dto.MeterDTO;
import com.smsc.headend.module.asset.entity.ComEntity;
import com.smsc.headend.module.asset.entity.Dcu;
import com.smsc.headend.module.asset.entity.DeviceRelation;
import com.smsc.headend.module.asset.entity.Meter;
import com.smsc.headend.module.protocol.DeviceData;
import com.smsc.headend.module.report.entity.LogUnRegisterMeterHis;
import com.smsc.headend.module.task.dto.AtomicTask;
import com.smsc.headend.module.task.dto.Task;
import com.smsc.headend.module.task.enums.TaskType;
import com.smsc.headend.task.engine.dao.TaskDAO;
import com.smsc.headend.task.engine.exception.UDISTaskHandlerException;
import com.smsc.headend.task.engine.handler.TaskHandler;
import com.smsc.headend.task.engine.mapper.DeviceRelationMapper;
import com.smsc.headend.task.engine.service.FeignAssetManagementService;
import com.smsc.headend.task.engine.service.asset.AssetService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author liangli
 * @date 2020/9/15
 */
@Slf4j
public class SetMeterListHandler implements TaskHandler {
    @Autowired
    FeignAssetManagementService assetManagementService;
    @Autowired
    TaskDAO taskDAO;
    @Autowired
    DeviceRelationMapper deviceRelationMapper;
    @Autowired
    AssetService assetService;

    @Override
    public int handle(Task task, AtomicTask atomicTask, DeviceData cosemData, String actionResult) throws UDISTaskHandlerException {
        log.info("SetMeterList success,taskNo={}", task.getTaskNo());
        if("Success".equals(actionResult)) {
            Map<String, Object> map = JSONUtil.toBean(task.getParamJson(), Map.class);
            List<Long> meterIds = (List<Long>) ((List) map.get("meterIds")).stream().map(o -> Long.valueOf(String.valueOf(o))).collect(Collectors.toList());
            for (Long meterId : meterIds) {
                MeterDTO meterDTO = new MeterDTO();
                meterDTO.setMeterId(meterId);
                meterDTO.setManageStatus(Meter.MeterManageStatus.Managed.getCode());
                meterDTO.setMountStatus(Meter.MeterMountStatus.Mounted.getCode());
                assetManagementService.updateMeterStatus(meterDTO);

                Meter meter = assetManagementService.getMeterById(meterId);
                assetManagementService.updateMeterStatus(meterDTO);

                if (assetManagementService.deleteUnRegisterRecordByDeviceSn(meter.getMfgSn()) == 1) {
                    log.info("remove the unregister record success");
                }
            }
            ComEntity comEntity = assetService.getComById(task.getComId());
            if (comEntity != null) {
                Dcu dcu = assetManagementService.getDcuById(comEntity.getDeviceId());
                // 导入该DCU挂接的表计，下发白名单成功后，修改DCU 状态为Installed
                DcuDTO dcuDTO = new DcuDTO();
                dcuDTO.setDcuId(dcu.getDcuId());
                dcuDTO.setInstallStatus(Dcu.DcuInstallStatus.Installed.getCode());
                assetManagementService.updateDcuStatus(dcuDTO);
            }

            taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), String.valueOf(task.getComId()), meterIds,
                    Long.valueOf(1 * 60 * 60), true);

            if (StrUtil.equalsAny(task.getTaskType(), TaskType.DcuPushUnRegisterMeter.toString(), TaskType.DcuManualUnRegisterMeter.toString())) {
                handleDcuRegisterSuccessAction(meterIds, task);
            }
        } else {
            taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), String.valueOf(task.getComId()), actionResult,
                    Long.valueOf(1 * 60 * 60), false);
        }

        return 1;
    }
    private void handleDcuRegisterSuccessAction(List<Long> meterIds, Task task) {
        // Dcu自注册流程 如果表计和dcu没有relation 需要建立relation关系
        for (Long meterId : meterIds) {
            DeviceRelation deviceRelation = deviceRelationMapper.selectById(meterId);
            ComEntity comEntity = assetService.getComById(task.getComId());
            if (null == deviceRelation ) {
                addNewDeviceRelation(meterId, comEntity.getDeviceId());
            } else if(!deviceRelation.getParentId().equals(comEntity.getDeviceId())){
                //删除旧的关系 插入新的relation
                log.info("remove the old relation between meterId {}, dcuId {}", meterId, deviceRelation.getParentId());
                deviceRelationMapper.delete(Wrappers.<DeviceRelation>lambdaQuery().eq(DeviceRelation::getDeviceId, meterId).eq(DeviceRelation::getDeviceType, DeviceType.METER.getId()));
                addNewDeviceRelation(meterId, comEntity.getDeviceId());
            }
            assetManagementService.saveUnregisterMeterHis(meterId, comEntity.getDeviceId(), task.getTaskNo(), LogUnRegisterMeterHis.ActionType.SetMeterList.getCode(),
                    task.getTaskType().equals(TaskType.DcuPushUnRegisterMeter.toString()) ? LogUnRegisterMeterHis.UnRegisterSrc.Auto.getCode() : LogUnRegisterMeterHis.UnRegisterSrc.Manual.getCode(), LogUnRegisterMeterHis.UnRegisterStatus.SUCCESS.getCode(), null, SystemClock.now() / 1000, "Set MeterList Completed");

        }
    }

    /**
     * 增加表计和dcu的relation关系
     */
    private void addNewDeviceRelation(Long meterId, Long parentId) {
        DeviceRelation newDeviceRelation = new DeviceRelation();
        newDeviceRelation.setDeviceId(meterId);
        newDeviceRelation.setDeviceType(DeviceType.METER.getId());
        newDeviceRelation.setParentId(parentId);
        newDeviceRelation.setParentType(DeviceType.DCU.getId());
        deviceRelationMapper.insert(newDeviceRelation);
        log.info("add new deviceRelation , meterId {}", meterId);
    }



    @Override
    public int handleFailure(Task task, AtomicTask atomicTask, String message) {
        log.error("SetMeterList failed,taskNo={},message={}", task.getTaskNo(), message);
        taskDAO.addTaskData(task.getTaskNo(), atomicTask.getAtomicTaskNo(), "message", message, 3600l, false);
        if (StrUtil.equalsAny(task.getTaskType(), TaskType.DcuPushUnRegisterMeter.toString(), TaskType.DcuManualUnRegisterMeter.toString())) {
            log.error("failed message {}", message);
            // 记录更新自注册流程失败的record
            Map<String, Object> map = JSONUtil.toBean(task.getParamJson(), Map.class);
            List<Long> meterIds = (List<Long>) ((List) map.get("meterIds")).stream().map(o -> Long.valueOf(String.valueOf(o))).collect(Collectors.toList());
            ComEntity comEntity = assetService.getComById(task.getComId());
            for (Long meterId : meterIds) {
                Meter meter = assetManagementService.getMeterById(meterId);
                assetManagementService.saveUnRegisterRecord(meter.getMfgSn(), comEntity.getDeviceId(), null, "Set Meter List Failed");
                assetManagementService.saveUnregisterMeterHis(meterId, comEntity.getDeviceId(), task.getTaskNo(), LogUnRegisterMeterHis.ActionType.SetMeterList.getCode(),
                        task.getTaskType().equals(TaskType.DcuPushUnRegisterMeter.toString()) ? LogUnRegisterMeterHis.UnRegisterSrc.Auto.getCode() : LogUnRegisterMeterHis.UnRegisterSrc.Manual.getCode(),
                        LogUnRegisterMeterHis.UnRegisterStatus.FAILED.getCode(), null, SystemClock.now() / 1000, message);

            }
        }
        return -1;
    }
}
